﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Input;

using System.Diagnostics;
using System.Threading;
using System.IO;

namespace FontManager
{
    public class XNAHelper
    {
        #region variables
        /// <summary>
        /// determines if the cursor should be hand of default one
        /// </summary>
        public bool DRAW_LINE_DRAG_CURSOR { get; set; }
        /// <summary>
        /// indicates if the mouse if over the lines
        /// </summary>
        public bool OVER_THE_LINE { get; set; }
        //Font lines
        /// <summary>
        /// Font line used to be draw on the preview window
        /// </summary>
        public static FontLine LINE_X;
        //Font lines
        /// <summary>
        /// Font line used to be draw on the preview window
        /// </summary>
        public static FontLine LINE_MULTI_BASE;
        //Font lines
        /// <summary>
        /// Font line used to be draw on the preview window
        /// </summary>
        public static FontLine LINE_LEADING;
        //Font lines
        /// <summary>
        /// Font line used to be draw on the preview window
        /// </summary>
        public static FontLine LINE_X_HEIGHT;
        //Font lines
        /// <summary>
        /// Font line used to be draw on the preview window
        /// </summary>
        public static FontLine LINE_CAP_HEIGHT;
        //Font lines
        /// <summary>
        /// Font line used to be draw on the preview window
        /// </summary>
        public static FontLine LINE_ASCENDER_HEIGHT;
        //Font lines
        /// <summary>
        /// Font line used to be draw on the preview window
        /// </summary>
        public static FontLine LINE_DESCENDER_HEIGHT;
        //Font lines
        /// <summary>
        /// Font line used to be draw on the preview window
        /// </summary>
        public static FontLine LINESpace_BEGIN;
        //Font lines
        /// <summary>
        /// Font line used to be draw on the preview window
        /// </summary>
        public static FontLine LINESpace_END;
        //Font lines
        /// <summary>
        /// Font line used to be draw on the preview window
        /// </summary>
        public static FontLine LINEKerning_BEGIN;
        //Font lines
        /// <summary>
        /// Font line used to be draw on the preview window
        /// </summary>
        public static FontLine LINEKerning_END;
        
        /// <summary>
        /// Preview window size
        /// </summary>
        public int PREVIEW_WIDTH, PREVIEW_HEIGHT;
        /// <summary>
        /// Space and Kerning are used only when the characters are drawed and they depend on their value.
        /// With that in mind I need to have their location extracted so I could have more control over it.
        /// </summary>
        float LINESpace_BEGIN_LOCATION, LINEKerning_BEGIN_LOCATION;

        /// <summary>
        /// 1x1 black pixel used to draw lines
        /// </summary>
        Texture2D LINE_TEXTURE;
        /// <summary>
        /// Font used to write on preview window
        /// </summary>
        SpriteFont SPRITE_FONT;
        /// <summary>
        /// The list of customTexture2D which represents characters wanted to be draw on the preview window.
        /// Each character in this list contains its location and connected info.
        /// </summary>
        List<CustomTexture2D> PREVIEWCharacters;
        /// <summary>
        /// Camera object.
        /// </summary>
        public Camera2D PREVIEW_CAMERA;
        /// <summary>
        /// used for reinitializing previewCharacters list.
        /// </summary>
        private GraphicsDevice GRAPHICS;
        /// <summary>
        /// controls the transperancy of the lines
        /// </summary>
        public static float Alpha = .5f;
        #endregion

        #region constructors
        /// <summary>
        /// initializes viewport, empty camera and lines.
        /// </summary>
        /// <param _name="width">the width of the window</param>
        /// <param _name="height">the height of the window</param>
        /// <param _name="graphics">graphicsDevice object</param>
        public XNAHelper(int width, int height, GraphicsDevice graphics)
        {
            this.GRAPHICS = graphics;
            this.DRAW_LINE_DRAG_CURSOR = false;
            PREVIEW_WIDTH = width;
            PREVIEW_HEIGHT = height;

            PREVIEW_CAMERA = new Camera2D();
            init();
            INITIALIZE();
        }

        /// <summary>
        /// is newFont in MainForm is not null initializes horizontal lines.
        /// </summary>
        public void INITIALIZE()
        {
            if (MainForm.NEW_FONT != null)
            {
                initLinesHorizontal(true,true,true,true,true,true,true);
            }
        }
        #endregion

        #region LoadContent
        /// <summary>
        /// load lines pixel texture and font.
        /// </summary>
        /// <param _name="content">contentManager</param>
        public void LoadContent(ContentManager content)
        {
            SPRITE_FONT = content.Load<SpriteFont>(@"Font\dummyFont");
            LINE_TEXTURE = content.Load<Texture2D>(@"Dummy\pixel");
        }
        #endregion

        #region Update
        /// <summary>
        /// the old state of the mouse
        /// </summary>
        MouseState oldState;
        /// <summary>
        /// controls if preview characters needs to be reinitialized.
        /// Have this to prevent unnecessary reinitialization of the objects.
        /// </summary>
        public static bool REINIT_PREVIEWCHARACTERS = true;
        /// <summary>
        /// main update method which doesn't do much except calling preview_update, updating old mouse state and passing parameters.
        /// </summary>
        /// <param _name="mouseState">mouse state passed from Game1</param>
        /// <param _name="mousedelta">for zooming. if > 0 _zoom incr. if !> decreases </param>
        public void Update(MouseState mouseState, int mousedelta)
        {
            PREVIEW_UPDATE(mouseState, mousedelta);
            oldState = mouseState;
        }
        #endregion

        #region Update Preview 
        /// <summary>
        /// rectangle containing mouse location and 1x1 size rectangle.
        /// </summary>
        Rectangle mouseRect;
        /// <summary>
        /// creates _inverse matric and applies it to mouse position which is later used to create _mouseRectangle object.
        /// If font not null check if mouse if over the line and if mouse if clicked.
        /// </summary>
        /// <param _name="mouseState">mouse state passed from Game1</param>
        /// <param _name="mousedelta">for zooming. if > 0 _zoom incr. if !> decreases </param>
        private void PREVIEW_UPDATE(MouseState mouseState, int mousedelta)
        {
            Matrix inverse = Matrix.Invert(PREVIEW_CAMERA.GetTransformation());
            Vector2 mousePosition = Vector2.Transform(new Vector2(mouseState.X, mouseState.Y), inverse);
            mouseRect = new Rectangle((int)mousePosition.X, (int)mousePosition.Y, 1, 1);

            if (MainForm.NEW_FONT != null)
            {
                mouseOverTheLine(mouseRect);

                if (MainForm.NEW_FONT.LineBase)
                    mouseClick_MoveLine(LINE_X, ref mouseState, ref mouseRect);
                if (MainForm.NEW_FONT.LineMultiBase)
                    mouseClick_MoveLine(LINE_MULTI_BASE, ref mouseState, ref mouseRect);

                if (MainForm.NEW_FONT.LineLeading)
                    mouseClick_MoveLine(LINE_LEADING, ref mouseState, ref mouseRect);
                if (MainForm.NEW_FONT.LineXHeight)
                    mouseClick_MoveLine(LINE_X_HEIGHT, ref mouseState, ref mouseRect);
                if (MainForm.NEW_FONT.LineCapHeight)
                    mouseClick_MoveLine(LINE_CAP_HEIGHT, ref mouseState, ref mouseRect);
                if (MainForm.NEW_FONT.LineAscenderHeight)
                    mouseClick_MoveLine(LINE_ASCENDER_HEIGHT, ref mouseState, ref mouseRect);
                if (MainForm.NEW_FONT.LineDescenderHeight)
                    mouseClick_MoveLine(LINE_DESCENDER_HEIGHT, ref mouseState, ref mouseRect);
                if (MainForm.NEW_FONT.LineSpace)
                    mouseClick_MoveLine(LINESpace_END, ref mouseState, ref mouseRect);
                if (MainForm.NEW_FONT.LineKerning)
                    mouseClick_MoveLine(LINEKerning_END, ref mouseState, ref mouseRect);

                if (REINIT_PREVIEWCHARACTERS)
                {
                    initLinesHorizontal(true, true, true, true, true, true, true);
                    LINESpace_BEGIN_LOCATION = 0;
                    LINEKerning_BEGIN_LOCATION = 0;
                    PREVIEWCharacters.Clear();
                    initPreviewCharacters(true);
                    initPreviewCharacters(false);
                    REINIT_PREVIEWCHARACTERS = false;

                    initLinesVertical();
                }
            }
            #region scaling
            if (mousedelta > 0)
            {
                PREVIEW_CAMERA.Zoom += 0.25f;
            }
            if (mousedelta < 0)
            {
                PREVIEW_CAMERA.Zoom -= 0.25f;
            }
            #endregion
        }

        /// <summary>
        /// if mouse if over the line makes the line red and line.MouseHover true.
        /// if line's _name X or MULTI_BASE ignores the rest of the code.
        /// When left button is pressed all lines are setted to be unmovable except the one its intersects;
        /// Lines is moved and font properties updated.
        /// If old mouse state button us down and a new mouse state button up changes LineColor of the line back, reinits preview characters,
        /// sets draw line to false and MouseHover to false.
        /// </summary>
        /// <param _name="line">line</param>
        /// <param _name="mouseState">mouse state</param>
        /// <param _name="_mouseRectangle">mouse rectangle</param>
        private void mouseClick_MoveLine(FontLine line, ref MouseState mouseState, ref Rectangle mouseRect)
        {

            if (mouseRect.Intersects(line.GetSourceRectangle))
            {
                line.LineColor = Color.Red;
                line.MouseHover = true;
            }
            else
            {
                line.LineColor = Color.Black;
                line.MouseHover = false;
            }

            if (line.Name != "X" && line.Name != "MULTI_BASE")
            {
                if (mouseState.LeftButton == ButtonState.Pressed)
                {
                    if (mouseRect.Intersects(line.GetSourceRectangle))
                    {
                        resetLines();
                        line.Move = true;
                        line.LineColor = Color.Red;
                        line.MouseHover = true;
                        DRAW_LINE_DRAG_CURSOR = true;
                    }
                    if (line.Move)
                    {
                        if (line.Height == 1)
                        {
                            line.Y = mouseRect.Y;
                        }
                        if (line.Width == 1)
                        {
                            line.X = mouseRect.X;
                        }
                        updateFont(line.Name);
                        if (line.Name == "DescenderHeight")
                            initLinesHorizontal(false, false, true, false, false, false, false);
                    }
                }

                if (mouseState.LeftButton == ButtonState.Released)
                {
                    line.Move = false;
                    if (oldState.LeftButton == ButtonState.Pressed && mouseState.LeftButton == ButtonState.Released)
                    {
                        line.LineColor = Color.Black;
                        DRAW_LINE_DRAG_CURSOR = false;
                        line.MouseHover = false;
                        REINIT_PREVIEWCHARACTERS = true;
                    }
                }
            }
        }
        /// <summary>
        /// updates font properties after the lines been moved
        /// </summary>
        /// <param _name="lineName">capitalized _name which is hardcoded on creation of the line</param>
        private void updateFont(string lineName)
        {
            switch (lineName)
            {
                case "Leading":
                    MainForm.NEW_FONT.Leading = LINE_LEADING.Y - (LINE_X.Y + MainForm.NEW_FONT.DescenderHeight);
                    break;

                case "XHeight":
                    MainForm.NEW_FONT.XHeight = LINE_X.Y - LINE_X_HEIGHT.Y;
                    break;

                case "CapHeight":
                    MainForm.NEW_FONT.CapHeight = LINE_X.Y - LINE_CAP_HEIGHT.Y;
                    break;

                case "AscenderHeight":
                    MainForm.NEW_FONT.AscenderHeight = LINE_X.Y - LINE_ASCENDER_HEIGHT.Y;
                    break;

                case "DescenderHeight":
                    MainForm.NEW_FONT.DescenderHeight = LINE_DESCENDER_HEIGHT.Y - LINE_X.Y;
                    break;

                case "SPACE_END":
                    MainForm.NEW_FONT.Space = LINESpace_END.X - LINESpace_BEGIN.X;
                    break;

                case "Kerning_END":
                    MainForm.NEW_FONT.Kerning = LINEKerning_END.X - LINEKerning_BEGIN.X;
                    break;
            }
        }

        /// <summary>
        /// determines if the mouse is stationed over any line.
        /// </summary>
        /// <param _name="_mouseRectangle">mouse rectangle with size 1x1</param>
        private void mouseOverTheLine(Rectangle mouseRect)
        {
            if (mouseRect.Intersects(LINE_LEADING.GetSourceRectangle))
            {
                OVER_THE_LINE = true;
            }
            if (mouseRect.Intersects(LINE_X_HEIGHT.GetSourceRectangle))
            {
                OVER_THE_LINE = true;
            }
            if (mouseRect.Intersects(LINE_CAP_HEIGHT.GetSourceRectangle))
            {
                OVER_THE_LINE = true;
            }
            if (mouseRect.Intersects(LINE_ASCENDER_HEIGHT.GetSourceRectangle))
            {
                OVER_THE_LINE = true;
            }
            if (mouseRect.Intersects(LINE_DESCENDER_HEIGHT.GetSourceRectangle))
            {
                OVER_THE_LINE = true;
            }
            if (mouseRect.Intersects(LINESpace_END.GetSourceRectangle))
            {
                OVER_THE_LINE = true;
            }
            if (mouseRect.Intersects(LINEKerning_END.GetSourceRectangle))
            {
                OVER_THE_LINE = true;
            }
            else
            {
                OVER_THE_LINE = false;
            }
        }
        #endregion

        #region Draw
        /// <summary>
        /// updates camera position, based on _zoom using either PointClamp(for pixelated _zoom) or LinearClamp(nicer looking, blury image).
        /// if font != null draws characters and lines with camera transformation applied.
        /// </summary>
        /// <param _name="spriteBatch"></param>
        public void Draw(SpriteBatch spriteBatch)
        {
            PREVIEW_CAMERA.Pos = new Vector2(PREVIEW_WIDTH, PREVIEW_HEIGHT);
            SamplerState st = new SamplerState();
            if (PREVIEW_CAMERA.Zoom > 2f)
                st = SamplerState.PointClamp;
            if (PREVIEW_CAMERA.Zoom <= 2f)
                st = SamplerState.LinearClamp; 
            
            if (MainForm.NEW_FONT != null)
            {
                spriteBatch.Begin(SpriteSortMode.BackToFront, null, st, null, null, null, PREVIEW_CAMERA.GetTransformation());
                DrawPreviewChars(spriteBatch);
                DrawLines(spriteBatch);
                spriteBatch.End();

                spriteBatch.Begin();
                DrawLinesText(spriteBatch);
                spriteBatch.End();
            }
        }

        /// <summary>
        /// based on mainfomr.Font object retermines which lines shall be drawed.
        /// </summary>
        /// <param _name="spriteBatch"></param>
        private void DrawLines(SpriteBatch spriteBatch)
        {
            if (MainForm.NEW_FONT.LineBase)
            {
                DrawLine(spriteBatch, LINE_X);
            }
            if(MainForm.NEW_FONT.LineMultiBase)
            {
                DrawLine(spriteBatch, LINE_MULTI_BASE);
            }
            if (MainForm.NEW_FONT.LineLeading)
            {
                DrawLine(spriteBatch, LINE_LEADING);
            }
            if (MainForm.NEW_FONT.LineXHeight)
            {
                DrawLine(spriteBatch, LINE_X_HEIGHT);
            }
            if (MainForm.NEW_FONT.LineCapHeight)
            {
                DrawLine(spriteBatch, LINE_CAP_HEIGHT);
            }
            if (MainForm.NEW_FONT.LineAscenderHeight)
            {
                DrawLine(spriteBatch, LINE_ASCENDER_HEIGHT);
            }
            if (MainForm.NEW_FONT.LineDescenderHeight)
            {
                DrawLine(spriteBatch, LINE_DESCENDER_HEIGHT);
            }
            if (MainForm.NEW_FONT.LineSpace)
            {
                DrawLine(spriteBatch, LINESpace_BEGIN);
                DrawLine(spriteBatch, LINESpace_END);
            }
            if (MainForm.NEW_FONT.LineKerning)
            {
                DrawLine(spriteBatch, LINEKerning_BEGIN);
                DrawLine(spriteBatch, LINEKerning_END);
            }
        }
        /// <summary>
        /// draws a font line using lines texture,source rectangle, LineColor.
        /// </summary>
        /// <param _name="spriteBatch"></param>
        /// <param _name="Line"></param>
        private void DrawLine(SpriteBatch spriteBatch, FontLine Line)
        {
            Color c = Line.LineColor;
            spriteBatch.Draw(LINE_TEXTURE, Line.GetSourceRectangle, new Color(c.R,c.G,c.B,Alpha));
        }
        /// <summary>
        /// runs through methods and draws the line over which the mouse is stationed.
        /// </summary>
        /// <param _name="spriteBatch"></param>
        private void DrawLinesText(SpriteBatch spriteBatch)
        {
            DrawLineText(spriteBatch, LINE_X);
            DrawLineText(spriteBatch, LINE_ASCENDER_HEIGHT);
            DrawLineText(spriteBatch, LINE_CAP_HEIGHT);
            DrawLineText(spriteBatch, LINE_DESCENDER_HEIGHT);
            DrawLineText(spriteBatch, LINEKerning_BEGIN);
            DrawLineText(spriteBatch, LINEKerning_END);
            DrawLineText(spriteBatch, LINE_LEADING);
            DrawLineText(spriteBatch, LINE_MULTI_BASE);
            DrawLineText(spriteBatch, LINESpace_BEGIN);
            DrawLineText(spriteBatch, LINESpace_END);
            DrawLineText(spriteBatch, LINE_X_HEIGHT);
        }
        /// <summary>
        /// draws a font line text using lines parameters and mouse rectangle location for drawing location.
        /// </summary>
        /// <param _name="spriteBatch"></param>
        /// <param _name="line"></param>
        private void DrawLineText(SpriteBatch spriteBatch, FontLine line)
        {
            if (line.MouseHover)
            {
                spriteBatch.DrawString(SPRITE_FONT, line.Name, new Vector2(mouseRect.X+10, mouseRect.Y), new Color(line.LineColor.R, line.LineColor.G, line.LineColor.B, Alpha));
            }
        }

        /// <summary>
        /// draws all the characters from previewCharacters list using customTexture2D values for it.
        /// </summary>
        /// <param _name="spriteBatch"></param>
        private void DrawPreviewChars(SpriteBatch spriteBatch)
        {
            foreach (CustomTexture2D c in PREVIEWCharacters)
                spriteBatch.Draw(c.Texture2d, c.Position, Color.White);
        }

        #endregion

        #region initialization
        /// <summary>
        /// Initialize empty lines, preview character list and preview camera.
        /// </summary>
        private void init()
        {
            initLines();
            PREVIEWCharacters = new List<CustomTexture2D>();
            PREVIEW_CAMERA.init(PREVIEW_WIDTH, PREVIEW_HEIGHT);
        }

        private void initLines()
        {
            LINE_X = new FontLine();
            LINE_MULTI_BASE = new FontLine();
            LINE_LEADING = new FontLine();
            LINE_X_HEIGHT = new FontLine();
            LINE_CAP_HEIGHT = new FontLine();
            LINE_ASCENDER_HEIGHT = new FontLine();
            LINE_DESCENDER_HEIGHT = new FontLine();
            LINESpace_BEGIN = new FontLine();
            LINESpace_END = new FontLine();
            LINEKerning_BEGIN = new FontLine();
            LINEKerning_END = new FontLine();

            LINE_X.Name = "X";
            LINE_MULTI_BASE.Name = "MULTI_BASE";
            LINE_LEADING.Name = "Leading";
            LINE_X_HEIGHT.Name = "XHeight";
            LINE_CAP_HEIGHT.Name = "CapHeight";
            LINE_ASCENDER_HEIGHT.Name = "AscenderHeight";
            LINE_DESCENDER_HEIGHT.Name = "DescenderHeight";
            LINESpace_BEGIN.Name = "SPACE_BEGIN";
            LINESpace_END.Name = "SPACE_END";
            LINEKerning_BEGIN.Name = "Kerning_BEGIN";
            LINEKerning_END.Name = "Kerning_END";
        }

        /// <summary>
        /// reinits when viewport size is changed
        /// if font is not null reinitializes lines and drawed characters.
        /// </summary>
        /// <param _name="newWidth"></param>
        /// <param _name="newHeight"></param>
        public void reInitialize(int newWidth, int newHeight)
        {
            this.PREVIEW_WIDTH = newWidth;
            this.PREVIEW_HEIGHT = newHeight;

            if (MainForm.NEW_FONT != null)
            {
                initLinesHorizontal(true, true, true, true, true, true, true);
                REINIT_PREVIEWCHARACTERS = true;
            }
        }

        /// <summary>
        /// Initialize.. horizontal lines based on Font properties.
        /// </summary>
        private void initLinesHorizontal(bool x, bool secondX, bool leading, bool xheight, bool capHeight, bool ascender, bool descender)
        {
            if (x)
            {
                LINE_X.Initialize(5, this.PREVIEW_HEIGHT / 2, this.PREVIEW_WIDTH - 10, 1);
            }
            if (secondX)
            {
                float multiLineY = LINE_X.Y + MainForm.NEW_FONT.AscenderHeight + MainForm.NEW_FONT.DescenderHeight + MainForm.NEW_FONT.Leading;
                LINE_MULTI_BASE.Initialize(LINE_X.X, multiLineY, LINE_X.Width, 1);
            }
            if (leading)
            {
                LINE_LEADING.Initialize(LINE_X.X, LINE_X.Y + MainForm.NEW_FONT.Leading + MainForm.NEW_FONT.DescenderHeight, LINE_X.Width, 1);
            }
            if (xheight)
            {
                LINE_X_HEIGHT.Initialize(LINE_X.X, LINE_X.Y - MainForm.NEW_FONT.XHeight, LINE_X.Width, 1);
            }
            if (capHeight)
            {
                LINE_CAP_HEIGHT.Initialize(LINE_X.X, LINE_X.Y - MainForm.NEW_FONT.CapHeight, LINE_X.Width, 1);
            }
            if (ascender)
            {
                LINE_ASCENDER_HEIGHT.Initialize(LINE_X.X, LINE_X.Y - MainForm.NEW_FONT.AscenderHeight, LINE_X.Width, 1);
            }
            if (descender)
            {
                LINE_DESCENDER_HEIGHT.Initialize(LINE_X.X, LINE_X.Y + MainForm.NEW_FONT.DescenderHeight, LINE_X.Width, 1);
            }
        }

        /// <summary>
        /// inits vertical lines based on newfont and preview window characters.
        /// for this to work initTopLinePreviewCharacters() needs to be initialized.
        /// </summary>
        private void initLinesVertical()
        {
            LINESpace_BEGIN.Initialize(LINESpace_BEGIN_LOCATION, 5, 1, this.PREVIEW_HEIGHT - 10);
            LINESpace_END.Initialize(LINESpace_BEGIN.X + MainForm.NEW_FONT.Space, LINESpace_BEGIN.Y, 1, LINESpace_BEGIN.Height);
            LINEKerning_BEGIN.Initialize(LINEKerning_BEGIN_LOCATION, 5, 1, this.PREVIEW_HEIGHT - 10);
            LINEKerning_END.Initialize(LINEKerning_BEGIN.X + MainForm.NEW_FONT.Kerning, LINEKerning_BEGIN.Y, 1, LINEKerning_BEGIN.Height);

        }

        /// <summary>
        /// deals with images creation and load at runtime.
        /// creates an character[] from font.message and after applying the TextAlignment checks the list of characters for character[].
        /// each character is then drawed and loaded to customTexture2D. (TOP LINE)
        /// </summary>
        public void initPreviewCharacters(bool topLine)
        {
            string characters = "";
            if (topLine)
            {
                characters = MainForm.NEW_FONT.Message;
            }
            if (!topLine)
            {
                characters = MainForm.NEW_FONT.MessageTwo;
            }

            //creating a list of strings where we are storring all the character values needed
            //==============================================================================
            string[] charactersHex = new string[characters.Length];
            for (int i = 0; i < characters.Length; i++)
            {
                char c = characters[i];
                int unicode = c;
                charactersHex[i] = string.Format("0x{0:x4}", unicode);
            }
            //makes the text be drawed at the center of the screen
            //==============================================================================
            float X = 0;

            switch (MainForm.NEW_FONT.TextAlignment)
            {
                case FontFont.textAlign.Center:
                    X = getAllignmentX(FontFont.textAlign.Center, measureString(charactersHex));
                    break;
                case FontFont.textAlign.Left:
                    X = getAllignmentX(FontFont.textAlign.Left, measureString(charactersHex));
                    break;
                case FontFont.textAlign.Right:
                    X = getAllignmentX(FontFont.textAlign.Right, measureString(charactersHex));
                    break;
            }
            //==============================================================================
            foreach (string s in charactersHex)
            {
                if (MainForm.NEW_FONT.ContainsCharHEX(s) || "0x0020" == s)
                {
                    for (int i = 0; i < MainForm.NEW_FONT.Characters.Count; i++)
                    {
                        if (MainForm.NEW_FONT.Characters[i].Name == s)
                        {
                            float Y = 0;
                            if (topLine)
                            {
                                 Y = LINE_X.Y - MainForm.NEW_FONT.Characters[i].AnchorPoint.Y;
                            }
                            if (!topLine)
                            {
                                 Y = LINE_X.Y - MainForm.NEW_FONT.Characters[i].AnchorPoint.Y
                                + MainForm.NEW_FONT.AscenderHeight + MainForm.NEW_FONT.DescenderHeight + MainForm.NEW_FONT.Leading;
                            }

                            CustomTexture2D ct2d = new CustomTexture2D();
                            ct2d.Texture2d = getTextureFromFile(MainForm.NEW_FONT.Characters[i].Image, GRAPHICS);
                            ct2d.X = X;
                            ct2d.Y = Y;
                            ct2d.Uri = MainForm.NEW_FONT.Characters[i].Image;
                            ct2d.HexName = s;
                            ct2d.Anchor = new Vector2(MainForm.NEW_FONT.Characters[i].AnchorPoint.X, MainForm.NEW_FONT.Characters[i].AnchorPoint.Y);
                            PREVIEWCharacters.Add(ct2d);

                            X += (MainForm.NEW_FONT.Kerning - MainForm.NEW_FONT.Characters[i].AnchorPoint.X + MainForm.NEW_FONT.Characters[i].Width);

                            //Initialize Kerning lines location
                            if (LINEKerning_BEGIN_LOCATION == 0)
                                LINEKerning_BEGIN_LOCATION = X;
                            break;
                        }
                        //space character
                        if ("0x0020" == s)
                        {
                            if (LINESpace_BEGIN_LOCATION == 0)
                                LINESpace_BEGIN_LOCATION = X;
                            X += MainForm.NEW_FONT.Space;
                            break;
                        }
                    }
                }
            }
        }


        
        #endregion

        #region Helper methods
        /// <summary>
        /// sets all lines to unmovable mode
        /// </summary>
        public void resetLines()
        {
            LINE_X.Move = false;
            LINE_MULTI_BASE.Move = false;
            LINE_LEADING.Move = false;
            LINE_X_HEIGHT.Move = false;
            LINE_CAP_HEIGHT.Move = false;
            LINE_ASCENDER_HEIGHT.Move = false;
            LINE_DESCENDER_HEIGHT.Move = false;
            LINESpace_BEGIN.Move = false;
            LINESpace_END.Move = false;
            LINEKerning_BEGIN.Move = false;
            LINEKerning_END.Move = false;
        }

        /// <summary>
        /// measures the length of the string which will used later on for alignment purposes.
        /// </summary>
        /// <param _name="charactersHex">list of characters HEX</param>
        /// <returns>the length of character list message</returns>
        private float measureString(string[] charactersHex)
        {
            float textLength = 0;
            foreach (string s in charactersHex)
            {
                if (MainForm.NEW_FONT.ContainsCharHEX(s) || "0x0020" == s)
                {
                    for (int i = 0; i < MainForm.NEW_FONT.Characters.Count; i++)
                    {
                        if (MainForm.NEW_FONT.Characters[i].Name == s)
                        {
                            textLength += (MainForm.NEW_FONT.Kerning - MainForm.NEW_FONT.Characters[i].AnchorPoint.X + MainForm.NEW_FONT.Characters[i].Width);
                            break;
                        }
                        //space character
                        if ("0x0020" == s)
                        {
                            textLength += MainForm.NEW_FONT.Space;
                            break;
                        }
                    }
                }
            }
            return textLength;
        }

        /// <summary>
        /// based on alignment type and textlenght returns the X value of where the characters
        /// shall be started to be draw to achive it.
        /// </summary>
        /// <param _name="align">can be textAlign.Center | Left | Right</param>
        /// <param _name="textLength">value of measureString(string[])</param>
        /// <returns></returns>
        private float getAllignmentX(FontFont.textAlign align, float textLength)
        {
            float X = 0;
            if (MainForm.NEW_FONT.TextAlignment == FontFont.textAlign.Center)
            {
                    X = (PREVIEW_WIDTH - textLength) / 2;
            }

            if (MainForm.NEW_FONT.TextAlignment == FontFont.textAlign.Left)
            {
                X = LINE_X.X;
            }

            if (MainForm.NEW_FONT.TextAlignment == FontFont.textAlign.Right)
            {
                    X = PREVIEW_WIDTH - textLength;
            }
            return X;
        }

        /// <summary>
        /// loads the image at runtime 
        /// </summary>
        /// <param _name="path">image path</param>
        /// <param _name="graphics">graphics device</param>
        /// <returns>texture2D of given iamge path</returns>
        public Texture2D getTextureFromFile(string path, GraphicsDevice graphics)
        {
            FileStream fs = new FileStream(path, FileMode.Open,FileAccess.Read, FileShare.Read);
            Texture2D t2d = Texture2D.FromStream(graphics, fs);
            fs.Close();
            return t2d;
        }
        #endregion

    }
}
